package com.bci.pwtz.service.cad.d;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Reader;
import java.io.Writer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.log4j.Logger;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Component;

import com.bci.pwtz.common.PwtzConstants;
import com.bci.pwtz.controller.AbstractController;
import com.bci.pwtz.exception.PwtzDatabaseException;
import com.bci.pwtz.exception.PwtzException;
import com.bci.pwtz.service.impl.BusinessCommonServiceImpl;

@Component
public class DyOper {
	private final Logger _log = Logger.getLogger(this.getClass());
	private Map<Long,String> layers = new HashMap<Long, String>();
	
	private static final String CAD_LAYER = "layer s %s \r\n"; 
	private static final String CAD_INSERT = "insert %s %f,%f   0\r\n";
	private static final String CAD_TEXT = "text %f,%f 0.25 0 %s\r\n";
	private static final String CAD_LINE = "line %f,%f %f,%f \r\n";
	private static final String CAD_RECTANG = "rectang 0,0 %f,%f\r\n";
	
	public DyOper() {
		layers.put((long)AbstractController.配电变压器, "变压器");
		layers.put((long)AbstractController.柱上变压器, "变压器");
		layers.put((long)AbstractController.低压杆塔, "杆塔");
		layers.put((long)AbstractController.低压表箱, "表箱");
		layers.put((long)AbstractController.低压电缆分接箱, "电缆分接箱");
		layers.put((long)AbstractController.低压配电箱, "配电箱");
		layers.put((long)AbstractController.低压熔丝箱, "熔丝箱");
		layers.put((long)AbstractController.低压剩余电流保护器, "剩余电流保护器");
		layers.put((long)AbstractController.低压导线, "导线");
		layers.put((long)AbstractController.低压电缆, "电缆");
	}
	
	/**
	 * 通过变电站画cad图（主入口）
	 * @param path 文件路径
	 * @param companyID 公司id
	 * @param deviceID 变电站id
	 * @return 文件路径
	 * @throws PwtzException 
	 */
	public String draw(String path,Long companyID,String deviceID,Long deviceType) throws PwtzException{
		if(deviceType != 1 && deviceType != 2){
			return null;
		}
		List<Device> allDeviceList = new ArrayList<Device>();
		List<Line> allLineList = new ArrayList<Line>();
		String tableName = BusinessCommonServiceImpl.TABLE_NAME_MAP.get(deviceType);
		//查询变压器
		String sql = "SELECT DeviceId,DeviceName,Longitude,Latitude FROM "+tableName+" WHERE CompanyID = ? AND DeviceId = ? and Status = 1";
		Device bdz = jdbcTemplate.queryForObject(sql,new Device.DeviceRowMapper(deviceType.intValue()),new Object[]{companyID,deviceID});
		allDeviceList.add(bdz);
		_log.debug("查询变电压器成功:"+bdz);
		
		//查询低压线路
		sql = "SELECT deviceID FROM T_DYXL WHERE TransformerCode = ? and Status = 1";
		List<String> zyxlList =  jdbcTemplate.queryForList(sql, String.class,new Object[]{deviceID});
		_log.debug("变电站下的线路列表:"+zyxlList);
		
		_log.debug("开始查询设备列表.....");
		List<Device> deviceList = queryDevice(zyxlList);
		allDeviceList.addAll(deviceList);
		_log.debug("结束查询设备列表:"+deviceList);
		
		_log.debug("开始查询导线、电缆列表.....");
		List<Line> lineList =  queryLine(zyxlList,allDeviceList);
		allLineList.addAll(lineList);
		_log.debug("结束查询导线、电缆列表："+lineList);
		
		//连接变电站和第一个杆塔
		if(deviceList!=null && allDeviceList.size()>2){
			Device zygt = allDeviceList.get(1);
			int lineType = AbstractController.低压导线;
			String lineName = "";
			String startDeviceID = bdz.getDeviceID();
			String endDeviceID = zygt.getDeviceID();
			Point startPoint = bdz.getPoint();
			Point endPoint = zygt.getPoint();
			Line line = new Line(lineType, lineName, startDeviceID, endDeviceID, startPoint, endPoint);
			allLineList.add(line);
		}
		
		_log.debug("开始缩放所有设备的坐标....");
		//最小、最大经纬度
		Point minLonLat = getMinPoint(allDeviceList).getLonLat();
		Point maxLonLat = getMaxPoint(allDeviceList).getLonLat();
		
		//移动坐标
		moveOf(allDeviceList);
		
//		double d1 = Math.floor(100.0D * (getMinRange(allDeviceList) / 4.5));
		double d1 = Math.floor(100.0D * (getMaxRange(allDeviceList) / 100));
		//最小距离为100
		if(d1 < 200){
			d1 = 200;
		}
		double ratio = d1/200; 
		//按比例缩放
		changeRatio(allDeviceList, ratio);
		
		//按比例缩放后，在移动一段距离，避免画出设备被挡
		moveOf(allDeviceList,new Point(40, 10));
		_log.debug("结束缩放所有设备的坐标.");
//		if(allDeviceList.size()>0)
//		allDeviceList.remove(0);
//		if(allLineList.size()>0)
//		allLineList.remove(0);
		_log.debug("开始绘制cad图....");
		StringBuffer drawInfo = new StringBuffer();
		drawInfo.append(String.format("text 15.488000,2.500000 1.000000 0 %d米\r\n", (int)(ratio*100)));
		for(Device device : allDeviceList){
			String layer = layers.get(Long.valueOf(device.getDeviceType()));
			Point point = device.getPoint();
			double x = point.getX();
			double y = point.getY();
			String deviceName = device.getDeviceName();
			double fontWidth = getTextSize(deviceName, 1.5);
			drawInfo.append(String.format(CAD_LAYER,layer));
			drawInfo.append(String.format(CAD_INSERT, layer,x,y));
			if(device.getDeviceType()==4){
				drawInfo.append(String.format(CAD_TEXT, x-fontWidth/2+2,y+3-2,deviceName));
			}else{
				drawInfo.append(String.format(CAD_TEXT, x-fontWidth/2+2,y+1-2,deviceName));
			}
			
		}
		for(Line line : allLineList){
			Point startPoint = line.getStartPoint();
			Point endPoint = line.getEndPoint();
			String layer = layers.get(Long.valueOf(line.getLineType()));
			drawInfo.append(String.format(CAD_LAYER,layer));
			drawInfo.append(String.format(CAD_LINE, startPoint.getX(),startPoint.getY(),endPoint.getX(),endPoint.getY()));
		}
		
		Point maxPoit = getMaxPoint(allDeviceList);
		drawInfo.append(String.format(CAD_RECTANG,maxPoit.getX()+10,maxPoit.getY()+10));
		
		drawInfo.append(String.format(CAD_LINE, 30F,10F,36F,10F));
		drawInfo.append(String.format(CAD_LINE, 33F,7F,33F,13F));
		drawInfo.append(String.format(CAD_TEXT, 36F,7F,"地图参照坐标:经度 "+minLonLat.getX()+" 纬度 "+minLonLat.getY()));
		
		drawInfo.append(String.format(CAD_LINE, maxPoit.getX()-3,maxPoit.getY(),maxPoit.getX()+3,maxPoit.getY()));
		drawInfo.append(String.format(CAD_LINE, maxPoit.getX(),maxPoit.getY()+3,maxPoit.getX(),maxPoit.getY()-3));
		drawInfo.append(String.format(CAD_TEXT, maxPoit.getX()+3,maxPoit.getY()-3,"地图参照坐标:经度 "+maxLonLat.getX()+" 纬度 "+maxLonLat.getY()));
		_log.debug("结束绘制cad图:"+drawInfo.toString());
		
		String fileName = writeFile(path, drawInfo.toString());
		return fileName;
	}
	
	/**
	 * 遍历所属线路下的【中压杆塔、中压开关站、中压配电室、中压环网柜、中压电缆分支箱、柱上变压器、配电变压器】
	 * @param zyxlList 中压线路id集合
	 * @return 
	 */
	private List<Device> queryDevice(List<String> zyxlList){
		List<Device> allDeviceList = new ArrayList<Device>();
		//遍历所属线路下的设备
		for(String zyxl : zyxlList){
			//将要获取的设备列表
			long[] deviceTypes = {
					AbstractController.低压杆塔,
					AbstractController.低压表箱,
					AbstractController.低压电缆分接箱,
					AbstractController.低压配电箱,
					AbstractController.低压剩余电流保护器,
					};
			
			//获取该线路下的所有设备
			for(long deviceType : deviceTypes){
				String tableName = BusinessCommonServiceImpl.TABLE_NAME_MAP.get(deviceType);
				String sql = String.format("SELECT DeviceId,DeviceName,Longitude,Latitude FROM %s WHERE LineCode = ? and Status = 1", tableName);
				List<Device> deviceList =  jdbcTemplate.query(sql, new Device.DeviceRowMapper((int)deviceType),zyxl);
				allDeviceList.addAll(deviceList);
			}
		}
		return allDeviceList;
	}
	
	/**
	 * 遍历所属线路下的【中压导线、中压电缆】
	 * @param zyxlList 线路id集合
	 * @param allDeviceList 设备集合
	 * @return
	 */
	private List<Line> queryLine(List<String> zyxlList,List<Device> allDeviceList){
		List<Line> allLineList = new ArrayList<Line>();
		for(String zyxl : zyxlList){
			long[] lineTypes = {AbstractController.低压导线,AbstractController.低压电缆};
			String[][] lineColumns = {
					{"StartTowerCode","EndTowerCode"},
					{"StartDeviceCode","EndDeviceCode"}
			};
			for(int i = 0; i < lineTypes.length; i++){
				long lineType = lineTypes[i];
				String tableName = BusinessCommonServiceImpl.TABLE_NAME_MAP.get(lineType);
				String sql = String.format("SELECT DeviceName,%s,%s FROM %s WHERE LineCode = ? and Status = 1",lineColumns[i][0],lineColumns[i][1],tableName );
				RowMapper<Line> rowMapper = new Line.LineRowMapper("DeviceName", lineColumns[i][0],lineColumns[i][1], (int)lineType, allDeviceList);
				List<Line> lineList = jdbcTemplate.query(sql, rowMapper,zyxl);
				allLineList.addAll(lineList);
			}
		}
		return allLineList;
	}
	
	/**
	 * 获取设备的最小坐标
	 * @param allDeviceList 所有设备
	 * @return
	 */
	private Point getMinPoint(List<Device> allDeviceList){
		double minX = 0;
		double minY = 0;
		for(Device device : allDeviceList){
			double x = device.getPoint().getX();
			double y = device.getPoint().getY();
			if(minX == 0){
				minX = x;
			}
			if(minY == 0){
				minY = y;
			}
			minX = Math.min(minX, x);
			minY = Math.min(minY, y);
		}
		
		return new Point(minX, minY);
	}
	/**
	 * 获取设备的最大坐标
	 * @param allDeviceList 所有设备
	 * @return
	 */
	private Point getMaxPoint(List<Device> allDeviceList){
		double maxX = 0;
		double maxY = 0;
		for(Device device : allDeviceList){
			double x = device.getPoint().getX();
			double y = device.getPoint().getY();
			maxX = Math.max(maxX, x);
			maxY = Math.max(maxY, y);
		}
		
		return new Point(maxX, maxY);
	}
	
	/**
	 * 获取最小距离
	 * @return
	 */
	private double getMinRange(List<Device> allDeviceList){
		double minRange = 10000;
		for(int i = 0; i < allDeviceList.size(); i++){
			for(int j = i+1; j < allDeviceList.size(); j++){
				Point point1 = allDeviceList.get(i).getPoint();
				Point point2 = allDeviceList.get(j).getPoint();
				double side1 = point1.getX() - point2.getX();
				double side2 = point1.getY() - point2.getY();
				double range = Math.sqrt(side1*side1+side2*side2);
				minRange = Math.min(minRange, range);
			}
		}
		
		return minRange;
	}
	
	/**
	 * 获取最大距离
	 * @return
	 */
	private double getMaxRange(List<Device> allDeviceList){
		double maxRange = 0;
		for(int i = 0; i < allDeviceList.size(); i++){
			for(int j = i+1; j < allDeviceList.size(); j++){
				Point point1 = allDeviceList.get(i).getPoint();
				Point point2 = allDeviceList.get(j).getPoint();
				double side1 = point1.getX() - point2.getX();
				double side2 = point1.getY() - point2.getY();
				double range = Math.sqrt(side1*side1+side2*side2);
				maxRange = Math.max(maxRange, range);
			}
		}
		
		return maxRange;
	}
	
	
	/**
	 * 移动坐标
	 * @param allDeviceList
	 */
	private void moveOf(List<Device> allDeviceList){
		Point minPoint = getMinPoint(allDeviceList);
		for(Device device : allDeviceList){
			double x = -minPoint.getX();
			double y = -minPoint.getY();
			device.getPoint().moveOf(x,y);
		}
	}
	/**
	 * 移动坐标
	 * @param allDeviceList
	 */
	private void moveOf(List<Device> allDeviceList,Point point){
		for(Device device : allDeviceList){
			device.getPoint().moveOf(point);
		}
	}
	/**
	 * 比例缩放
	 * @param allDeviceList
	 */
	private void changeRatio(List<Device> allDeviceList,double ratio){
		for(Device device : allDeviceList){
			device.getPoint().changeRatio(ratio);
		}
	}
	
	private static double getTextSize(String showName, double db) {
		int i = 0;
		int j = 0;
		for (int k = 0; k < showName.length(); k++) {
			if (showName.charAt(k) > '') {
				j++;
			} else {
				i++;
			}
		}
		return (db * (0.96D * i + 0.725D * j));
	}
	
	private String writeFile(String path,String data) throws PwtzException{
		String fileName = System.currentTimeMillis()+".scr";
		
		BufferedWriter bufferedWriter = null;
		try {
			File file = new File(path);
			if(!file.exists()){
				file.mkdirs();
			}
			
			OutputStream out = new FileOutputStream(path+fileName);
			Writer writer = new OutputStreamWriter(out, "GBK");
			bufferedWriter = new BufferedWriter(writer);
			
			writeHead(bufferedWriter);
			bufferedWriter.write(data);
			bufferedWriter.write("osmode 20647\r\n");
			bufferedWriter.write("zoom a\r\n");
			bufferedWriter.write("layer s 0 ");
//			bufferedWriter.write("\r\n");//本地服务器需加
			bufferedWriter.flush();
			
		} catch (Exception e) {
			_log.error("单线图【写入文件】失败", e);
			throw new PwtzException(e);
		} finally{
			if(bufferedWriter != null){
				try {
					bufferedWriter.close();
				} catch (IOException e) {
					_log.error("单线图写入文件【关闭流】失败", e);
				}
			}
		}
		
		return fileName;
	}
	private BufferedWriter writeHead(BufferedWriter bufferedWriter) throws PwtzException{
		String headPath = PwtzConstants.WEB_REAL_PATH+"/cad/dhead.txt";
		BufferedReader br = null;
		try {
			InputStream in = new FileInputStream(headPath);
			Reader reader = new InputStreamReader(in,"GBK");
			br = new BufferedReader(reader);
			
			String info = null;
			while( (info = br.readLine()) != null ){
				bufferedWriter.write(info);
				bufferedWriter.newLine();
			}
			
		} catch (Exception e) {
			_log.error("中压单线图【读取头文件】失败。", e);
			throw new PwtzException(e);
		} finally{
			if(br!=null){
				try {
					br.close();
				} catch (IOException e) {
					_log.error("中压单线图读取头【关闭流】失败。", e);
				}
			}
		}
		
		return bufferedWriter;
	}
	
	private JdbcTemplate jdbcTemplate;
	
	public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
		this.jdbcTemplate = jdbcTemplate;
	}
	
}
